package com.gollum.web.service;

import com.aliyun.oss.*;
import com.aliyun.oss.model.*;
import com.gollum.common.constant.SysConfigConstants;
import com.gollum.common.constant.SystemConstants;
import com.gollum.common.exception.UploadException;
import com.gollum.system.service.SysConfigService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * 阿里云对象存储服务
 *
 * @author Herther
 * @createTime 2022年10月24日 21:40:00
 * @since 1.0.0
 */
@Component
@Slf4j
public class AliyunOssService {



    @Autowired
    protected SysConfigService sysConfigService;



    /**
     * 构建OSS对象
     * @return OSS
     * @auther: Herther
     * @since 1.0.0
     * @date: 2022/10/24 21:57
     */
    public OSS buildOssClient(){
        /** 端点 **/
        String endpoint = sysConfigService.getConfigValue(SysConfigConstants.ALIYUN_OSS_ENDPOINT);
        /** 令牌ID **/
         String keyId = sysConfigService.getConfigValue(SysConfigConstants.ALIYUN_OSS_ACCESS_KEY_ID);
        /** 令牌密钥  **/
         String keySecret = sysConfigService.getConfigValue(SysConfigConstants.ALIYUN_OSS_ACCESS_KEY_SECRET);
        return new OSSClientBuilder().build(endpoint, keyId, keySecret);
    }


    /**
     * 上传网络流
     *
     * @param Url 需要上传的来源网络的地址
     * @param objectName 上传文件的路径加上文件名 ，例如：test/gollum.html
     * @return 上传后的地址
     * @auther: Herther
     * @since 1.0.0
     * @date: 2022/10/24 22:02
     */
    public String uploadByNetworkStream(String Url,String objectName){
        OSS oss = null;
        try {
            URL url = new URL(Url);
            //获取存储桶
            String bucketName  = sysConfigService.getConfigValue(SysConfigConstants.ALIYUN_OSS_BUCKET);
            //获取输入流
            InputStream inputStream = url.openStream();
            //oss客户端
            oss = buildOssClient();
            exitBucketExit(oss,bucketName);
            //进行上传
            oss.putObject(bucketName, objectName, inputStream);
            //获取上传的地址
            return getUploadPath(objectName,bucketName);
        } catch (MalformedURLException e) {
            log.error("网络地址流有错误，请确定是否正确，错误内容为[{}]，输入内容为：[{}]", e.getMessage(),Url);
            throw new UploadException("请检查上传的地址是否有问题",500,e.toString());
        } catch (IOException e) {
            log.error("获取输入流失败,错误内容为[{}]，输入内容为：[{}]",e.getMessage(),Url);
            throw new UploadException("请检查上传的地址是否有问题",501,e.toString());
        } catch (OSSException e){
            log.error("上传出现异常,错误信息：[{}], 错误码：[{}]，请求ID：[{}]，地址ID为：[{}]", e.getMessage(),e.getErrorCode(),e.getRequestId(),e.getHostId());
            throw new UploadException("上传出现异常，请联系管理员",502,e.toString());
        } catch (ClientException e){
            log.error("与上传服务器连接失败：[{}]， 错误码：[{}]", e.getMessage(),e.getErrorCode());
            throw new UploadException("服务器断开，请联系管理员",503,e.toString());
        } finally {
            //关闭
            if (Objects.nonNull(oss)){
                oss.shutdown();
            }
        }
    }

    /**
     * 上传文件输入流
     *
     * @param inputStream 文件输入流
     * @param objectName 上传文件的路径加上文件名 ，例如：test/gollum.png
     * @return 上传后的新地址
     * @auther: Herther
     * @since 1.0.0
     * @date: 2022/10/24 22:29
     */
    public String uploadByInputStream(InputStream inputStream,String objectName){
        OSS oss = null;
        try {
            //获取存储桶
            String bucketName  = sysConfigService.getConfigValue(SysConfigConstants.ALIYUN_OSS_BUCKET);
            //oss客户端
            oss = buildOssClient();
            exitBucketExit(oss,bucketName);
            //进行上传
            oss.putObject(bucketName, objectName, inputStream);
            //获取上传的地址
            return getUploadPath(objectName,bucketName);
        }  catch (OSSException e){
            log.error("上传出现异常,错误信息：[{}], 错误码：[{}]，请求ID：[{}]，地址ID为：[{}]", e.getMessage(),e.getErrorCode(),e.getRequestId(),e.getHostId());
            throw new UploadException("上传出现异常，请联系管理员",502,e.toString());
        } catch (ClientException e){
            log.error("与上传服务器连接失败：[{}]， 错误码：[{}]", e.getMessage(),e.getErrorCode());
            throw new UploadException("服务器断开，请联系管理员",503,e.toString());
        } finally {
            //关闭
            if (Objects.nonNull(oss)){
                oss.shutdown();
            }
        }

    }

    /**
     * 上传文件流
     *
     * @param file 文件流
     * @param objectName 文件名
     * @return 上传后的新地址
     * @auther: Herther
     * @since 1.0.0
     * @date: 2022/10/24 22:29
     */
    public String uploadByFile(File file, String objectName){
        OSS oss = null;
        try {
            //获取存储桶
            String bucketName  = sysConfigService.getConfigValue(SysConfigConstants.ALIYUN_OSS_BUCKET);
            //oss客户端
            oss = buildOssClient();
            exitBucketExit(oss,bucketName);
            //进行上传
            oss.putObject(new PutObjectRequest(bucketName,objectName,file));
            //获取上传的地址
            return getUploadPath(objectName,bucketName);
        } catch (OSSException e){
            log.error("上传出现异常,错误信息：[{}], 错误码：[{}]，请求ID：[{}]，地址ID为：[{}]", e.getMessage(),e.getErrorCode(),e.getRequestId(),e.getHostId());
            throw new UploadException("上传出现异常，请联系管理员",502,e.toString());
        } catch (ClientException e){
            log.error("与上传服务器连接失败：[{}]， 错误码：[{}]", e.getMessage(),e.getErrorCode());
            throw new UploadException("服务器断开，请联系管理员",503,e.toString());
        } finally {
            //关闭
            if (Objects.nonNull(oss)){
                oss.shutdown();
            }
        }

    }

    /**
     * 判断文件存储桶是否存在如果不存在就创建
     *
     * @param oss 对象存储客户
     * @param bucketName 存储桶
     * @auther: Herther
     * @since 1.0.0
     * @date: 2022/10/24 22:46
     */
    public void exitBucketExit(OSS oss,String bucketName){
        if (oss.doesBucketExist(bucketName)){
            CreateBucketRequest createBucketRequest = new CreateBucketRequest(bucketName);
            //公开读取
            createBucketRequest.setCannedACL(CannedAccessControlList.PublicRead);
            oss.createBucket(createBucketRequest);
        }
    }

    /**
     * 根据key删除oss服务器上的文件
     * @param bucketName	存储桶名称
     * @param key 文件路径/名称  例如：test/gollum.txt
     * @auther: Herther
     * @since 1.0.0
     * @date: 2022/10/24 22:46
     */
    public Boolean deleteFile(String bucketName, String key) {
        OSS oss = null;
        try {
            //oss客户端
            oss = buildOssClient();
            //获取上传的地址
            oss.deleteObject(bucketName,key);
            return true;
        }  catch (OSSException e){
            log.error("删除文件异常,错误信息：[{}], 错误码：[{}]，请求ID：[{}]，地址ID为：[{}]", e.getMessage(),e.getErrorCode(),e.getRequestId(),e.getHostId());
            throw new UploadException("删除出现异常，请联系管理员",502,e.toString());
        } catch (ClientException e){
            log.error("与文件服务器连接失败：[{}]， 错误码：[{}]", e.getMessage(),e.getErrorCode());
            throw new UploadException("服务器断开，请联系管理员",503,e.toString());
        } finally {
            //关闭
            if (Objects.nonNull(oss)){
                oss.shutdown();
            }
        }
    }


    /**
     * 查询某个存储桶里面的所有文件
     * @param bucketName	存储桶名称
     * @return List<String>  文件路径和大小集合
     * @auther: Herther
     * @since 1.0.0
     * @date: 2022/10/24 22:46
     */
    public  List<String> queryAllObject(String bucketName) {
        List<String> results = new ArrayList<String>();
        OSS oss = null;
        try {
            //oss客户端
            oss = buildOssClient();
            ObjectListing objectListing = oss.listObjects(bucketName);
            //文件信息
            for (OSSObjectSummary objectSummary : objectListing.getObjectSummaries()) {
                results.add(" - " + objectSummary.getKey() + "  " + "(size = " + objectSummary.getSize() + ")");
            }
        }  catch (OSSException e){
            log.error("获取文件失败,错误信息：[{}], 错误码：[{}]，请求ID：[{}]，地址ID为：[{}]", e.getMessage(),e.getErrorCode(),e.getRequestId(),e.getHostId());
            throw new UploadException("获取文件失败，请联系管理员",502,e.toString());
        } catch (ClientException e){
            log.error("与文件服务器连接失败：[{}]， 错误码：[{}]", e.getMessage(),e.getErrorCode());
            throw new UploadException("服务器断开，请联系管理员",503,e.toString());
        } finally {
            //关闭
            if (Objects.nonNull(oss)){
                oss.shutdown();
            }
        }
        return results;
    }

    /**
     * 功能描述: 获取上传后的路径
     *
     * @param objectName 文件名称 例如：test/abvc.jpg
     * @param bucketName 存储桶名称
     * @return
     * @auther: Herther
     * @since 1.0.0
     * @date: 2022/10/28 22:27
     */
    public String getUploadPath(String objectName,String bucketName){
        StringBuilder newUrl = new StringBuilder(SystemConstants.HTTPS)
                .append(bucketName)
                .append(SystemConstants.POINT)
                .append(sysConfigService.getConfigValue(SysConfigConstants.ALIYUN_OSS_ENDPOINT));
        if (objectName.startsWith(SystemConstants.BACKSLASH)){
            newUrl.append(objectName);
        }else{
            newUrl.append(SystemConstants.BACKSLASH).append(objectName);
        }
        log.debug("上传成功后地址为：[{}]",newUrl.toString());
        return newUrl.toString();
    }

}